/**
 * 
 */
package soa.security.mgr.service.impl;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.naming.Name;

import org.apache.commons.lang3.StringUtils;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.support.LdapNameBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import soa.security.Constants;
import soa.security.domain.Organization;
import soa.security.domain.OrganizationUnit;
import soa.security.domain.Person;
import soa.security.domain.Position;
import soa.security.domain.Position.Positions;
import soa.security.exception.AdapterException;
import soa.security.exception.OrganizationException;
import soa.security.mgr.service.PositionMgrService;
import soa.security.util.BeanUtils;
import soa.security.util.JaxbUtils;

/**
 * @author Cre.Gu
 *
 */
@Service
public class PositionMgrServiceImpl extends BaseMgrServiceImpl implements
		PositionMgrService {
	protected final org.slf4j.Logger log = org.slf4j.LoggerFactory
			.getLogger(this.getClass());

	@Override
	public void addPosition(String organizationId, Position position)
			throws OrganizationException {
		try {
			if (StringUtils.isBlank(position.getBid())) {
				position.setBid("PO" + findMaxNumber(Position.class));

			}
			validate(position);
			validateOrganization(organizationId);

			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.POSITION);

			position.setDn(position.buildDn(unit.getDn()));
			positionDao.create(position);
		} catch (Exception e) {
			wrapException(e);
		}
	}

	@Override
	public void updatePosition(String organizationId, Position position)
			throws OrganizationException {
		try {
			validateOrganization(organizationId);
			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.POSITION);
			validatePosition(unit.getDn().toString(), position.getBid());

			Position up = positionDao.findByPrimaryKey(unit.getDn()
					.toString(), position.getBid());
			BeanUtils.copyPropertiesWithoutNull(position, up);
			position = up;
			
			validate(position);

			position.setDn(position.buildDn(unit.getDn()));
			positionDao.update(position);
		} catch (Exception e) {
			wrapException(e);
		}
	}

	private void validate(Position d) {
		Assert.hasText(d.getBid(), "岗位编码不能为空");
		Assert.hasText(d.getName(), "岗位名称不能为空");

		BeanUtils.blank2Null(d);
	}

	@Override
	public List<Position> allPositions(String organizationId)
			throws OrganizationException {
		return allPositions(organizationId, null, false);
	}

	@Override
	public List<Position> allPositions(String organizationId,
			Map<String, Object> parameters, boolean subTree)
			throws OrganizationException {
		List<Position> results = new ArrayList<Position>();
		try {
			validateOrganization(organizationId);

			if (subTree) {
				List<Organization> oneOrg = oneOrg(organizationId);
				for (Organization or : oneOrg) {
					results.addAll(doAllPositions(or.getBid(), parameters));
				}
			} else {
				results = doAllPositions(organizationId, parameters);
			}

		} catch (Exception e) {
			wrapException(e);
		}
		return results;
	}

	protected List<Position> doAllPositions(String organizationId,
			Map<String, Object> parameters) {
		List<Position> results = new ArrayList<Position>();

		OrganizationUnit unit = gainOrganizationUnit(organizationId,
				Constants.POSITION);

		results = positionDao.allPositions(unit.getDn().toString(),
				defaultSearchScope, parameters);

		sortResult(results);
		return results;
	}

	@Override
	public List<Position> allPositions(List<Position> all,
			List<Position> deptPositions) {
		Iterator<Position> iter = all.iterator();
		while (iter.hasNext()) {
			Position p = iter.next();
			boolean re = true;
			for (Position person : deptPositions) {
				if (p.getBid().equals(person.getBid())) {
					re = false;
					break;
				}
			}

			if (re)
				iter.remove();
		}
		return all;
	}

	@Override
	public List<Position> getPosition(String organizationId, String positionId)
			throws OrganizationException {
		List<Position> list = new ArrayList<Position>();
		try {
			validateOrganization(organizationId);
			OrganizationUnit unit = gainOrganizationUnit(organizationId,
					Constants.POSITION);
			validatePosition(unit.getDn().toString(), positionId);

			Name dn = LdapNameBuilder.newInstance(unit.getDn())
					.add(Constants.BID, positionId).build();
			list.add(positionDao.findByDn(dn.toString()));

		} catch (Exception e) {
			wrapException(e);
		}
		return list;
	}

	@Override
	public boolean addPersons(String organizationId, String positionId,
			String personIds) throws OrganizationException {
		try {
			validateOrganization(organizationId);

			OrganizationUnit poUnit = gainOrganizationUnit(organizationId,
					Constants.POSITION);
			validatePosition(poUnit.getDn().toString(), positionId);

			Position position = positionDao.findByPrimaryKey(poUnit.getDn()
					.toString(), positionId);

			String[] pids = StringUtils.split(personIds, ",");
			for (String pid : pids) {
				OrganizationUnit unit = gainOrganizationUnit(organizationId,
						Constants.PERSON);

				validatePerson(unit.getDn().toString(), pid);
				positionDao.addPersons(position, personDao.findByPrimaryKey(
						unit.getDn().toString(), pid));

			}

			return true;
		} catch (Exception e) {
			wrapException(e);
		}
		return false;
	}

	@Override
	public boolean removePersons(String organizationId, String positionId,
			String personIds) throws OrganizationException {
		try {
			validateOrganization(organizationId);

			OrganizationUnit poUnit = gainOrganizationUnit(organizationId,
					Constants.POSITION);
			validatePosition(poUnit.getDn().toString(), positionId);

			Position position = positionDao.findByPrimaryKey(poUnit.getDn()
					.toString(), positionId);

			String[] pids = StringUtils.split(personIds, ",");
			for (String pid : pids) {
				OrganizationUnit unit = gainOrganizationUnit(organizationId,
						Constants.PERSON);

				validatePerson(unit.getDn().toString(), pid);
				positionDao.removePersons(position, personDao.findByPrimaryKey(
						unit.getDn().toString(), pid));

			}

			return true;
		} catch (Exception e) {
			wrapException(e);
		}
		return false;
	}

	@Override
	public List<Person> allPersons(String organizationId, String positionId)
			throws OrganizationException {
		List<Person> list = new ArrayList<Person>();
		try {
			List<String> pids = super.positionPersons(organizationId,
					positionId);
			for (String string : pids) {
				list.add(personDao.findByDn(string));
			}
		} catch (Exception e) {
			wrapException(e);
		}
		return list;
	}

	@Override
	public List<Position> adapt(String xml) throws AdapterException {
		try {
			Positions bs = JaxbUtils.xml2Object(xml, Positions.class);
			return bs.getPosition();

		} catch (Exception e) {
			if (log.isDebugEnabled())
				log.debug("格式转换错误", e);
			throw new AdapterException(AdapterException.ERROR_01);
		}
	}

	@Override
	public String unadapt(List<Position> list) throws AdapterException {
		try {
			Positions bs = new Positions();
			bs.addAll(list);

			return JaxbUtils.object2Xml(bs, Positions.class);
		} catch (Exception e) {
			if (log.isDebugEnabled())
				log.debug("格式转换错误", e);
			throw new AdapterException(AdapterException.ERROR_01);
		}
	}

	@Override
	public Position findByDn(String dn) {
		try {
			return positionDao.findByDn(dn);

		} catch (Exception e) {
			printException(e);
			if (log.isDebugEnabled())
				log.debug("错误信息", e);

			return null;
		}
	}

	@Override
	public boolean deleteByDn(String dn) {
		try {
			positionDao.deleteByDn(dn);
			return true;
		} catch (Exception e) {
			printException(e);
			if (log.isDebugEnabled())
				log.debug("错误信息", e);

			return false;
		}
	}

	@Override
	public void addPosition4Mgr(String organizationId, Position model,
			String departmentIds, String personDns)
			throws OrganizationException {
		try {
			addPosition(organizationId, model);

			addOrRemoveDepartments4Mgr(organizationId, model, departmentIds);
			addOrRemovePersons4Mgr(organizationId, model, personDns);
		} catch (Exception e) {
			wrapException(e);
		}
	}

	@Override
	public void updatePosition4Mgr(String organizationId, Position model,
			String departmentIds, String personDns)
			throws OrganizationException {
		try {
			updatePosition(organizationId, model);

			addOrRemoveDepartments4Mgr(organizationId, model, departmentIds);
			addOrRemovePersons4Mgr(organizationId, model, personDns);
		} catch (Exception e) {
			wrapException(e);
		}
	}

	private void addOrRemoveDepartments4Mgr(String organizationId,
			Position position, String departmentDns) {
		// 原来的personIds
		List<String> origs = allDepartmentsDns(findDepartments(organizationId,
				Constants.POSITIONS, position.getDn().toString()));
		// form 提交的personIds
		List<String> forms = formIds(departmentDns);

		// 要增加的personIds
		List<String> adds = addIds(origs, forms);
		// 要删除的personIds
		List<String> rems = removeIds(origs, forms);

		ldapAddAttrName(adds, Constants.POSITIONS, position.getDn().toString());
		ldapRemoveAttrName(rems, Constants.POSITIONS, position.getDn()
				.toString());
	}

	private void addOrRemovePersons4Mgr(String organizationId,
			Position position, String personDns) {
		// 原来的personIds
		List<String> origs = positionDao.allPersons(position);
		// form 提交的personIds
		List<String> forms = formIds(personDns);

		// 要增加的personIds
		List<String> adds = addIds(origs, forms);
		// 要删除的personIds
		List<String> rems = removeIds(origs, forms);

		DirContextOperations context = ldapTemplate.lookupContext(position
				.getDn());

		for (String string : adds) {
			context.addAttributeValue(Constants.PERSONS, string);
		}
		for (String string : rems) {
			context.removeAttributeValue(Constants.PERSONS, string);
		}
		ldapTemplate.modifyAttributes(context);
	}

	@Override
	public void remove(String organizationId, String dn) {
		String[] dns = StringUtils.split(dn, ";");
		if (dns == null)
			return;

		for (String string : dns) {
			DirContextOperations context = ldapTemplate.lookupContext(string);

			context.setAttributeValue(Constants.DELETED, Constants.TRUE);
			ldapTemplate.modifyAttributes(context);

			// 删除关系
			// 部门
			List<String> rems = new ArrayList<String>();
			rems.addAll(allDepartmentsDns(findDepartments(organizationId,
					Constants.POSITIONS, dn)));

			ldapRemoveAttrName(rems, Constants.POSITIONS, dn);
		}
	}
}
